//#define PCL_NO_PRECOMPILE

#ifndef INPUTGEN_H_
#define INPUTGEN_H_
#include <iostream>
#include <vector>
#include <pcl/point_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/search/pcl_search.h>
#include <omp.h> // add before <pcl/keypoints/iss_3d.h>
#include <pcl/keypoints/iss_3d.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/conversions.h>
#include <pcl/features/fpfh_omp.h>
#include <pcl/features/fpfh.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/spin_image.h>
#include <Eigen/Core>
#include <pcl/io/pcd_io.h>
#include <Eigen/Geometry>
#include <pcl/features/3dsc.h>
#include <pcl/features/impl/3dsc.hpp>
#include <pcl/features/rops_estimation.h>
#include <pcl/surface/poisson.h>
#include <pcl/surface/gp3.h>
#include <pcl/filters/extract_indices.h>
#include "../SparseCoding/sparse.h"
#include "../SparseCoding/utils.h"
#include <pcl/common/transforms.h>
#include <pcl/registration/transformation_estimation_svd.h>
#include <pcl/features/normal_3d_omp.h>
using namespace std;
#include <algorithm>
//#include <vector>
//#include <pcl/point_types.h>
#include <pcl/pcl_macros.h>
#include <pcl/for_each_type.h>
#include <pcl/point_representation.h>
 
// struct corrTab{ //correspondence table, including the indices in corrIdx and the upperbound
//     int idxS; //first idx in corrIdx
//     int idxT; //second idx in corrIdx
//     int upBnd; //upperbound for this correspondences
//     int lwBnd;
//     double disFeature; //distance between the feature descriptors
// };
// namespace pcl{
    
//     struct MultiScaleF864{
//         float histogram[864];
//         static int descriptorSize(){return 864;}
//     };
//     template <>
//     class DefaultPointRepresentation <MultiScaleF864> : public PointRepresentation <MultiScaleF864>
//     {
// 	    public:
// 	    	DefaultPointRepresentation()
// 		    {
// 		    	nr_dimensions_ = 864;
// 			    trivial_ = false;
// 		    }
 
// 		    virtual void
// 		    	copyToFloatArray(const MultiScaleF864 &p, float * out) const
// 		    {
// 			    for (int i = 0; i < nr_dimensions_; ++i)
// 				    out[i] = p.histogram[i];
// 		    }
//     };
// }

namespace GenIn{
template<class T>
int length(T& arr)
{
    return sizeof(arr) / sizeof(arr[0]);
}

//voxel grid filter
void VGF(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr cloudVG,
	 double inlTh);
//ISS keypoint extraction
void ISSExt(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud, pcl::PointIndicesPtr pointsIdx,pcl::PointIndicesPtr ISSIdx, double inlTh);
//FPFH computation
void FPFHComp(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud,pcl::PointCloud<pcl::Normal>::Ptr normals, double inlTh, pcl::PointIndicesPtr ISSIdx, pcl::PointCloud<pcl::FPFHSignature33>& fpfhOut);
//spin image computation
void spinImageComp(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud,pcl::PointCloud<pcl::Normal>::Ptr normals,pcl::PointIndicesPtr ISSIdx, double radius,pcl::PointCloud<pcl::Histogram<153> >& spinImageOut);
//3DSC computation
void threeDSC(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud,pcl::PointCloud<pcl::Normal>::Ptr normals, pcl::PointIndicesPtr ISSIdx,double radius,pcl::PointCloud<pcl::ShapeContext1980>& threeSCOut);
//RoPS computation
//void RoPS(pcl::PointCloud<pcl::PointNormal>::ConstPtr cloud, pcl::PointIndicesPtr ISSIdx,double radius,pcl::PointCloud<pcl::Histogram <135> >& RoPSOut);
//multi features computation
void multiScaleSparseFeature(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud, pcl::PointIndicesPtr PointsIdx,pcl::PointIndicesPtr ISSIdx,double inlTh,int NumScale,std::vector<std::vector<double> > &FTVector_,std::vector<std::vector<double> > &NorFTVector_,vector<Param<Col> > &atom);
//normalized the features
void normalizeFT(std::vector<std::vector<double> > &FTVector);
//Sparse coding
void SparseCoding(const std::vector<std::vector<double> > FTVector,vector<Param<Col> > &atom);
//feature matching
void featureMatching(const vector<Param<Col> > sourceF,const vector<Param<Col> > targetF,bool sort_,std::vector<std::pair<int,int> > &best_matching,std::vector<pair<int,double> > &PCCsList);
//comparison function
bool cmp(const pair<int,double> a,const pair<int,double> b);
//mutual matching
void mutualMatching(const vector<Param<Col> > sourceF,const vector<Param<Col> > targetF,std::pair<int,int> &best_matching_pair,std::pair<double,double> &PCCs_pair);
//get the fine matching points
void getFineMatchingPoints(pcl::PointCloud<pcl::PointXYZ>::ConstPtr targetPC, pcl::PointCloud<pcl::PointXYZ>::ConstPtr sourcePC,std::vector<std::pair<int,int> > best_matching_pair_list,std::vector<std::vector<int> >pointIdxEightArea,pcl::PointCloud<pcl::PointXYZ> &targetFourPoints,pcl::PointCloud<pcl::PointXYZ> &sourceFourPoints);
//transformation calculation
void transformationCal(pcl::PointCloud<pcl::PointXYZ>::ConstPtr targetPC, pcl::PointCloud<pcl::PointXYZ>::ConstPtr sourcePC,
                       std::vector<std::pair<int,int> > best_matching_pair_list,std::vector<std::vector<int> >pointIdxEightArea,pcl::registration::TransformationEstimationSVD<pcl::PointXYZ,pcl::PointXYZ> ::Matrix4 &transformation);
//normal calculation
void calNoramls(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud,double radius,pcl::PointCloud<pcl::Normal>::Ptr normals);

// void corrComp(pcl::PointCloud<pcl::MultiScaleF864>::Ptr fpfhs,
//                                    pcl::PointCloud<pcl::MultiScaleF864>::Ptr fpfht,
//                                    vector<corrTab> &corr, int MaxNOCorrPP,
//                                    vector<int> &corrNOS, vector<int> &corrNOT);
}
#endif
